#!/usr/bin/python2.4
#
# -*- coding: utf-8 -*-
#
###############################################################
# Copyright 2006 Google Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
###############################################################


"""A JSON compatible feed builder.

Supporting build basic JSON date structure.
Require objson module.
Google Service using Gdata should subclass it and build its own
namespaces and notations.

For Gdata reference, please see:
http://code.google.com/apis/gdata/reference.html

Examples:

In [1]: import jsonbuilder
In [2]: j = jsonbuilder.JSON()
In [3]: feed = j.build('feed', attrs={'id':{'$t':'http://www.google.com'},
              'title':{'$t':'hello world'}})
In [4]: j.AddSubNode(feed)
In [5]: import objutils
In [6]: d = objutils.display
In [7]: d(j.root)
{'encoding': 'UTF-8',
 'feed': {'id': {'$t': 'http://www.google.com'},
          'title': {'$t': 'hello world'}},
 'version': '1.0'}

"""


__author__ = 'i3dmaster@gmail.com (Yongjian "Jim" Xu)'


import __builtin__
import sys
import objson
import objutils


_VMINOR = sys.version_info[1]

if _VMINOR <= 4:
  import struct


class Error(Exception):
  pass


class ObjectNotExistError(Error):
  pass


class JSON(object):
  """
  """
  def __init__(self, version=None, encoding=None):
    """
    """
    if version:
      self._version = version
    else:
      self._version = '1.0'
    if encoding:
      self._encoding = encoding
    else:
      self._encoding = 'UTF-8'

    json_ = {}
    json_['version'] = self._version
    json_['encoding'] = self._encoding

    self.__root = objson.OBJson(json_)

  def _getroot(self):
    return self.__root

  def _setroot(self, obj):
    if isinstance(obj, objson.OBJson):
      self.__root = obj
    else:
      raise objson.OBJsonTypeError, "root node MUST be an OBJson object."

  def _delroot(self):
    del self.__root

  root = property(_getroot, _setroot, _delroot, doc='get/set/del OBJson' \
          'top root node')

  def __repr__(self):
    """Override repr method to provide a package consistent object
    representation.
    """
    if _VMINOR <= 4:
      h = '%#x' % (long(__builtin__.id(self)) + \
          (1L << struct.calcsize('P') * 8))
    else:
      h = '%#x' % __builtin__.id(self)
    return '<%s:%s>' % (self.__class__.__name__, h)

  def __str__(self):
    """Return the string structure of the JSON data structure.
    """
    return objutils.ToJson(self.root)

  def build(self, name, attrs=None):
    """Factory method to build the python dictionary object representing
    the JSON structure.

    Args:
      name: the JSON element name.
      attrs: (optional) whether the element has any attributes. In
             the form of ({attr:val})

    Returns:
      Either a JSON root node or a JSON element object.

    Raises:
      ObjectAlreadyBuiltError, when the object has already built.
    """
    adict = {}
    if attrs:
      for k, v in attrs.iteritems():
        if k == '$t':
          adict['$t'] = u'%s' % v
        else:
          adict[k] = v
    return objson.genpyobj(name, adict, None)

  def AddSubNode(self, sub_node, node=None):
    """Wrapper to the OBJson object CreateChild method.

    Args:
      node: (optional) the object of which needs to add
            the sub_node to.
            default set to the root node.
      sub_node: the sub_node object.
    """
    if not node:
      node = self.root
    name = sub_node.GetName
    node.CreateChild(name, sub_node)

  def DelSubNode(self, sub_node, node=None):
    """Wrapper to the OBJson object DelChild method.

    Args:
      node: (optional) the parent node where the sub node belongs to.
            default set to the root node.
      sub_node: the sub_node that will be removed.
    """
    if not node:
      node = self.root
    node.DeleteChild(sub_node)

# Vim :set ts=2 sw=2 expandtab
# The End
